home *** CD-ROM | disk | FTP | other *** search
/ Nautilus 1993 March / Nautilus-4-3 / Nautilus-4-3.bin / Multimedia / Feature / RlePict1.1 Folder / lib / rle_getrow.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-08  |  14.9 KB  |  558 lines

  1. /*
  2.  * This software is copyrighted as noted below.  It may be freely copied,
  3.  * modified, and redistributed, provided that the copyright notice is 
  4.  * preserved on all copies.
  5.  * 
  6.  * There is no warranty or other guarantee of fitness for this software,
  7.  * it is provided solely "as is".  Bug reports or fixes may be sent
  8.  * to the author, who may or may not act on them as he desires.
  9.  *
  10.  * You may not include this software in a program or other software product
  11.  * without supplying the source, or without informing the end-user that the 
  12.  * source is available for no extra charge.
  13.  *
  14.  * If you modify this software, you should include a notice giving the
  15.  * name of the person performing the modification, the date of modification,
  16.  * and the reason for such modification.
  17.  *
  18.  *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
  19.  *  to have all "void" functions so declared.
  20.  */
  21. /* 
  22.  * rle_getrow.c - Read an RLE file in.
  23.  * 
  24.  * Author:    Spencer W. Thomas
  25.  *         Computer Science Dept.
  26.  *         University of Utah
  27.  * Date:    Wed Apr 10 1985
  28.  * Copyright (c) 1985 Spencer W. Thomas
  29.  * 
  30.  * $Id: rle_getrow.c,v 3.0.1.5 1992/03/04 19:33:08 spencer Exp $
  31.  */
  32. #ifndef lint
  33. static char rcs_ident[] = "$Id: rle_getrow.c,v 3.0.1.5 1992/03/04 19:33:08 spencer Exp $";
  34. #endif
  35.  
  36. #include "stdio.h"
  37. #include "rle.h"
  38. #include "rle_code.h"
  39.  
  40. /* Read a two-byte "short" that started in VAX (LITTLE_ENDIAN) order */
  41. #define VAXSHORT( var, fp )\
  42.     { var = fgetc(fp)&0xFF; var |= (fgetc(fp)) << 8; }
  43.   
  44. /* Instruction format -- first byte is opcode, second is datum. */
  45.  
  46. #define OPCODE(inst) (inst[0] & ~LONG)
  47. #define LONGP(inst) (inst[0] & LONG)
  48. #define DATUM(inst) (inst[1] & 0xff)    /* Make sure it's unsigned. */
  49.  
  50. static int       debug_f;        /* If non-zero, print debug info. */
  51. static void    bfill();
  52. extern int vax_gshort();
  53.  
  54. /*****************************************************************
  55.  * TAG( rle_get_setup )
  56.  * 
  57.  * Read the initialization information from an RLE file.
  58.  * Inputs:
  59.  *     the_hdr:    Contains pointer to the input file.
  60.  * Outputs:
  61.  *     the_hdr:    Initialized with information from the
  62.  *            input file.
  63.  *    Returns 0 on success, -1 if the file is not an RLE file,
  64.  *    -2 if malloc of the color map failed, -3 if an immediate EOF
  65.  *    is hit (empty input file), and -4 if an EOF is encountered reading
  66.  *    the setup information.
  67.  * Assumptions:
  68.  *     infile points to the "magic" number in an RLE file (usually
  69.  * byte 0 in the file).
  70.  * Algorithm:
  71.  *     Read in the setup info and fill in the_hdr.
  72.  */
  73. int
  74. rle_get_setup( the_hdr )
  75. rle_hdr * the_hdr;
  76. {
  77.     struct XtndRsetup setup;
  78.     short magic;
  79.     register FILE *infile = the_hdr->rle_file;
  80.     rle_pixel * bg_color;
  81.     register int i;
  82.     char * comment_buf;
  83.     
  84.     /* Clear old stuff out of the header. */
  85.     rle_hdr_clear( the_hdr );
  86.     if ( the_hdr->is_init != RLE_INIT_MAGIC )
  87.     rle_names( the_hdr, "Urt", "some file", 0 );
  88.     the_hdr->img_num++;        /* Count images. */
  89.  
  90.     VAXSHORT( magic, infile );
  91.     if ( feof( infile ) )
  92.     return RLE_EMPTY;
  93.     if ( magic != RLE_MAGIC )
  94.     return RLE_NOT_RLE;
  95.     fread( &setup, 1, SETUPSIZE, infile );  /* assume VAX packing */
  96.     if ( feof( infile ) )
  97.     return RLE_EOF;
  98.  
  99.     /* Extract information from setup */
  100.     the_hdr->ncolors = setup.h_ncolors;
  101.     for ( i = 0; i < the_hdr->ncolors; i++ )
  102.     RLE_SET_BIT( *the_hdr, i );
  103.  
  104.     if ( !(setup.h_flags & H_NO_BACKGROUND) && setup.h_ncolors > 0 )
  105.     {
  106.     the_hdr->bg_color = (int *)malloc(
  107.         (unsigned)(sizeof(int) * setup.h_ncolors) );
  108.     bg_color = (rle_pixel *)malloc(
  109.         (unsigned)(1 + (setup.h_ncolors / 2) * 2) );
  110.     RLE_CHECK_ALLOC( the_hdr->cmd, the_hdr->bg_color && bg_color,
  111.              "background color" );
  112.     fread( (char *)bg_color, 1, 1 + (setup.h_ncolors / 2) * 2, infile );
  113.     for ( i = 0; i < setup.h_ncolors; i++ )
  114.         the_hdr->bg_color[i] = bg_color[i];
  115.     free( bg_color );
  116.     }
  117.     else
  118.     {
  119.     (void)getc( infile );    /* skip filler byte */
  120.     the_hdr->bg_color = NULL;
  121.     }
  122.  
  123.     if ( setup.h_flags & H_NO_BACKGROUND )
  124.     the_hdr->background = 0;
  125.     else if ( setup.h_flags & H_CLEARFIRST )
  126.     the_hdr->background = 2;
  127.     else
  128.     the_hdr->background = 1;
  129.     if ( setup.h_flags & H_ALPHA )
  130.     {
  131.     the_hdr->alpha = 1;
  132.     RLE_SET_BIT( *the_hdr, RLE_ALPHA );
  133.     }
  134.     else
  135.     the_hdr->alpha = 0;
  136.  
  137.     the_hdr->xmin = vax_gshort( setup.hc_xpos );
  138.     the_hdr->ymin = vax_gshort( setup.hc_ypos );
  139.     the_hdr->xmax = the_hdr->xmin + vax_gshort( setup.hc_xlen ) - 1;
  140.     the_hdr->ymax = the_hdr->ymin + vax_gshort( setup.hc_ylen ) - 1;
  141.  
  142.     the_hdr->ncmap = setup.h_ncmap;
  143.     the_hdr->cmaplen = setup.h_cmaplen;
  144.     if ( the_hdr->ncmap > 0 )
  145.     {
  146.     register int maplen =
  147.              the_hdr->ncmap * (1 << the_hdr->cmaplen);
  148.     register int i;
  149.     register char *maptemp;
  150.  
  151.     the_hdr->cmap = (rle_map *)malloc(
  152.         (unsigned)(sizeof(rle_map) * maplen) );
  153.     maptemp = (char *)malloc( 2 * maplen );
  154.     if ( the_hdr->cmap == NULL || maptemp == NULL )
  155.     {
  156.         fprintf( stderr,
  157. "%s: Malloc failed for color map of size %d*%d in rle_get_setup, reading %s\n",
  158.              the_hdr->cmd,
  159.              the_hdr->ncmap, (1 << the_hdr->cmaplen),
  160.              the_hdr->file_name );
  161.         return RLE_NO_SPACE;
  162.     }
  163.     fread( maptemp, 2, maplen, infile );
  164.     for ( i = 0; i < maplen; i++ )
  165.         the_hdr->cmap[i] = vax_gshort( &maptemp[i * 2] );
  166.     free( maptemp );
  167.     }
  168.  
  169.     /* Check for comments */
  170.     if ( setup.h_flags & H_COMMENT )
  171.     {
  172.     short comlen, evenlen;
  173.     register char * cp;
  174.  
  175.     VAXSHORT( comlen, infile );    /* get comment length */
  176.     evenlen = (comlen + 1) & ~1;    /* make it even */
  177.     if ( evenlen )
  178.     {
  179.         comment_buf = (char *)malloc( (unsigned) evenlen );
  180.     
  181.         if ( comment_buf == NULL )
  182.         {
  183.         fprintf( stderr,
  184. "%s: Malloc failed for comment buffer of size %d in rle_get_setup, reading %s\n",
  185.              the_hdr->cmd, comlen, the_hdr->file_name );
  186.         return RLE_NO_SPACE;
  187.         }
  188.         fread( comment_buf, 1, evenlen, infile );
  189.         /* Count the comments */
  190.         for ( i = 0, cp = comment_buf; cp < comment_buf + comlen; cp++ )
  191.         if ( *cp == 0 )
  192.             i++;
  193.         i++;            /* extra for NULL pointer at end */
  194.         /* Get space to put pointers to comments */
  195.         the_hdr->comments =
  196.         (CONST_DECL char **)malloc( (unsigned)(i * sizeof(char *)) );
  197.         if ( the_hdr->comments == NULL )
  198.         {
  199.         fprintf( stderr,
  200.  "%s: Malloc failed for %d comment pointers in rle_get_setup, reading %s\n",
  201.              the_hdr->cmd, i, the_hdr->file_name );
  202.         return RLE_NO_SPACE;
  203.         }
  204.         /* Get pointers to the comments */
  205.         *the_hdr->comments = comment_buf;
  206.         for ( i = 1, cp = comment_buf + 1;
  207.           cp < comment_buf + comlen;
  208.           cp++ )
  209.         if ( *(cp - 1) == 0 )
  210.             the_hdr->comments[i++] = cp;
  211.         the_hdr->comments[i] = NULL;
  212.     }
  213.     else
  214.         the_hdr->comments = NULL;
  215.     }
  216.     else
  217.     the_hdr->comments = NULL;
  218.  
  219.     /* Initialize state for rle_getrow */
  220.     the_hdr->priv.get.scan_y = the_hdr->ymin;
  221.     the_hdr->priv.get.vert_skip = 0;
  222.     the_hdr->priv.get.is_eof = 0;
  223.     the_hdr->priv.get.is_seek = ftell( infile ) > 0;
  224.     debug_f = 0;
  225.  
  226.     if ( !feof( infile ) )
  227.     return RLE_SUCCESS;    /* success! */
  228.     else
  229.     {
  230.     the_hdr->priv.get.is_eof = 1;
  231.     return RLE_EOF;
  232.     }
  233. }
  234.  
  235.  
  236. /*****************************************************************
  237.  * TAG( rle_get_setup_ok )
  238.  * 
  239.  * Read the initialization information from an RLE file.
  240.  * Inputs:
  241.  *     the_hdr:    Contains pointer to the input file.
  242.  *    prog_name:  Program name to be printed in the error message.
  243.  *      file_name:  File name to be printed in the error message.
  244.  *                  If NULL, the string "stdin" is generated.
  245.  * Outputs:
  246.  *     the_hdr:    Initialized with information from the
  247.  *            input file.
  248.  *      If reading the header fails, it prints an error message
  249.  *    and exits with the appropriate status code.
  250.  * Algorithm:
  251.  *     rle_get_setup does all the work.
  252.  */
  253. void
  254. rle_get_setup_ok( the_hdr, prog_name, file_name )
  255. rle_hdr * the_hdr;
  256. CONST_DECL char *prog_name;
  257. CONST_DECL char *file_name;
  258. {
  259.     int code;
  260.  
  261.     /* Backwards compatibility: if is_init is not properly set, 
  262.      * initialize the header.
  263.      */
  264.     if ( the_hdr->is_init != RLE_INIT_MAGIC )
  265.     {
  266.     FILE *f = the_hdr->rle_file;
  267.     rle_hdr_init( the_hdr );
  268.     the_hdr->rle_file = f;
  269.     rle_names( the_hdr, prog_name, file_name, 0 );
  270.     }
  271.  
  272.     code = rle_get_error( rle_get_setup( the_hdr ),
  273.               the_hdr->cmd, the_hdr->file_name );
  274.     if (code)
  275.     exit( code );
  276. }
  277.  
  278.  
  279. /*****************************************************************
  280.  * TAG( rle_debug )
  281.  * 
  282.  * Turn RLE debugging on or off.
  283.  * Inputs:
  284.  *     on_off:        if 0, stop debugging, else start.
  285.  * Outputs:
  286.  *     Sets internal debug flag.
  287.  * Assumptions:
  288.  *    [None]
  289.  * Algorithm:
  290.  *    [None]
  291.  */
  292. void
  293. rle_debug( on_off )
  294. int on_off;
  295. {
  296.     debug_f = on_off;
  297.  
  298.     /* Set line buffering on stderr.  Character buffering is the default, and
  299.      * it is SLOOWWW for large amounts of output.
  300.      */
  301.     setlinebuf( stderr );
  302. }
  303.  
  304.  
  305. /*****************************************************************
  306.  * TAG( rle_getrow )
  307.  * 
  308.  * Get a scanline from the input file.
  309.  * Inputs:
  310.  *    the_hdr:    Header structure containing information about 
  311.  *            the input file.
  312.  * Outputs:
  313.  *     scanline:   an array of pointers to the individual color
  314.  *            scanlines.  Scanline is assumed to have
  315.  *            the_hdr->ncolors pointers to arrays of rle_pixel,
  316.  *            each of which is at least the_hdr->xmax+1 long.
  317.  *    Returns the current scanline number.
  318.  * Assumptions:
  319.  *     rle_get_setup has already been called.
  320.  * Algorithm:
  321.  *     If a vertical skip is being executed, and clear-to-background is
  322.  *    specified (the_hdr->background is true), just set the
  323.  *    scanlines to the background color.  If clear-to-background is
  324.  *    not set, just increment the scanline number and return.
  325.  * 
  326.  *    Otherwise, read input until a vertical skip is encountered,
  327.  *    decoding the instructions into scanline data.
  328.  *
  329.  *    If ymax is reached (or, somehow, passed), continue reading and
  330.  *    discarding input until end of image.
  331.  */
  332. int
  333. rle_getrow( the_hdr, scanline )
  334. rle_hdr * the_hdr;
  335. rle_pixel *scanline[];
  336. {
  337.     register rle_pixel * scanc;
  338.     register int nc;
  339.     register FILE *infile = the_hdr->rle_file;
  340.     int scan_x = the_hdr->xmin,    /* current X position */
  341.        channel = 0;            /* current color channel */
  342.     short word, long_data;
  343.     char inst[2];
  344.  
  345.     /* Clear to background if specified */
  346.     if ( the_hdr->background != 1 )
  347.     {
  348.     if ( the_hdr->alpha && RLE_BIT( *the_hdr, -1 ) )
  349.         bzero( (char *)scanline[-1] + the_hdr->xmin,
  350.            the_hdr->xmax - the_hdr->xmin + 1 );
  351.     for ( nc = 0; nc < the_hdr->ncolors; nc++ )
  352.         if ( RLE_BIT( *the_hdr, nc ) )
  353.         /* Unless bg color given explicitly, use 0. */
  354.         if ( the_hdr->background != 2 || the_hdr->bg_color[nc] == 0 )
  355.             bzero( (char *)scanline[nc] + the_hdr->xmin,
  356.                the_hdr->xmax - the_hdr->xmin + 1 );
  357.         else
  358.             bfill( (char *)scanline[nc] + the_hdr->xmin,
  359.                the_hdr->xmax - the_hdr->xmin + 1,
  360.                the_hdr->bg_color[nc] );
  361.     }
  362.  
  363.     /* If skipping, then just return */
  364.     if ( the_hdr->priv.get.vert_skip > 0 )
  365.     {
  366.     the_hdr->priv.get.vert_skip--;
  367.     the_hdr->priv.get.scan_y++;
  368.     if ( the_hdr->priv.get.vert_skip > 0 )
  369.         if ( the_hdr->priv.get.scan_y >= the_hdr->ymax )
  370.         {
  371.         int y = the_hdr->priv.get.scan_y;
  372.         while ( rle_getskip( the_hdr ) != 32768 )
  373.             ;
  374.         return y;
  375.         }
  376.         else
  377.         return the_hdr->priv.get.scan_y;
  378.     }
  379.  
  380.     /* If EOF has been encountered, return also */
  381.     if ( the_hdr->priv.get.is_eof )
  382.     return ++the_hdr->priv.get.scan_y;
  383.  
  384.     /* Otherwise, read and interpret instructions until a skipLines
  385.      * instruction is encountered.
  386.      */
  387.     if ( RLE_BIT( *the_hdr, channel ) )
  388.     scanc = scanline[channel] + scan_x;
  389.     else
  390.     scanc = NULL;
  391.     for (;;)
  392.     {
  393.     inst[0] = getc( infile );
  394.     inst[1] = getc( infile );
  395.     if ( feof(infile) )
  396.     {
  397.         the_hdr->priv.get.is_eof = 1;
  398.         break;        /* <--- one of the exits */
  399.     }
  400.  
  401.     switch( OPCODE(inst) )
  402.     {
  403.     case RSkipLinesOp:
  404.         if ( LONGP(inst) )
  405.         {
  406.         VAXSHORT( the_hdr->priv.get.vert_skip, infile );
  407.         }
  408.         else
  409.         the_hdr->priv.get.vert_skip = DATUM(inst);
  410.         if (debug_f)
  411.         fprintf(stderr, "Skip %d Lines (to %d)\n",
  412.             the_hdr->priv.get.vert_skip,
  413.             the_hdr->priv.get.scan_y +
  414.                 the_hdr->priv.get.vert_skip );
  415.  
  416.         break;            /* need to break for() here, too */
  417.  
  418.     case RSetColorOp:
  419.         channel = DATUM(inst);    /* select color channel */
  420.         if ( channel == 255 )
  421.         channel = -1;
  422.         scan_x = the_hdr->xmin;
  423.         if ( RLE_BIT( *the_hdr, channel ) )
  424.         scanc = scanline[channel]+scan_x;
  425.         if ( debug_f )
  426.         fprintf( stderr, "Set color to %d (reset x to %d)\n",
  427.              channel, scan_x );
  428.         break;
  429.  
  430.     case RSkipPixelsOp:
  431.         if ( LONGP(inst) )
  432.         {
  433.         VAXSHORT( long_data, infile );
  434.         scan_x += long_data;
  435.         scanc += long_data;
  436.         if ( debug_f )
  437.             fprintf( stderr, "Skip %d pixels (to %d)\n",
  438.                 long_data, scan_x );
  439.              
  440.         }
  441.         else
  442.         {
  443.         scan_x += DATUM(inst);
  444.         scanc += DATUM(inst);
  445.         if ( debug_f )
  446.             fprintf( stderr, "Skip %d pixels (to %d)\n",
  447.                 DATUM(inst), scan_x );
  448.         }
  449.         break;
  450.  
  451.     case RByteDataOp:
  452.         if ( LONGP(inst) )
  453.         {
  454.         VAXSHORT( nc, infile );
  455.         }
  456.         else
  457.         nc = DATUM(inst);
  458.         nc++;
  459.         if ( RLE_BIT( *the_hdr, channel ) )
  460.         {
  461.         fread( (char *)scanc, 1, nc, infile );
  462.         if ( nc & 1 )
  463.             (void)getc( infile );    /* throw away odd byte */
  464.         }
  465.         else
  466.         if ( the_hdr->priv.get.is_seek )
  467.             fseek( infile, ((nc + 1) / 2) * 2, 1 );
  468.         else
  469.         {
  470.             register int ii;
  471.             for ( ii = ((nc + 1) / 2) * 2; ii > 0; ii-- )
  472.             (void) getc( infile );    /* discard it */
  473.         }
  474.  
  475.         scanc += nc;
  476.         scan_x += nc;
  477.         if ( debug_f )
  478.         if ( RLE_BIT( *the_hdr, channel ) )
  479.         {
  480.             rle_pixel * cp = scanc - nc;
  481.             fprintf( stderr, "Pixel data %d (to %d):", nc, scan_x );
  482.             for ( ; nc > 0; nc-- )
  483.             fprintf( stderr, "%02x", *cp++ );
  484.             putc( '\n', stderr );
  485.         }
  486.         else
  487.         fprintf( stderr, "Pixel data %d (to %d)\n", nc, scan_x );
  488.         break;
  489.  
  490.     case RRunDataOp:
  491.         if ( LONGP(inst) )
  492.         {
  493.         VAXSHORT( nc, infile );
  494.         }
  495.         else
  496.         nc = DATUM(inst);
  497.         scan_x += nc + 1;
  498.  
  499.         VAXSHORT( word, infile );
  500.         if ( debug_f )
  501.         fprintf( stderr, "Run length %d (to %d), data %02x\n",
  502.                 nc + 1, scan_x, word );
  503.         if ( RLE_BIT( *the_hdr, channel ) )
  504.         {
  505.         if ( nc >= 10 )        /* break point for 785, anyway */
  506.         {
  507.             bfill( (char *)scanc, nc + 1, word );
  508.             scanc += nc + 1;
  509.         }
  510.         else
  511.             for ( ; nc >= 0; nc--, scanc++ )
  512.             *scanc = word;
  513.         }
  514.         break;
  515.  
  516.     case REOFOp:
  517.         the_hdr->priv.get.is_eof = 1;
  518.         if ( debug_f )
  519.         fprintf( stderr, "End of Image\n" );
  520.         break;
  521.  
  522.     default:
  523.         fprintf( stderr,
  524.              "%s: rle_getrow: Unrecognized opcode: %d, reading %s\n",
  525.              the_hdr->cmd, inst[0], the_hdr->file_name );
  526.         exit(1);
  527.     }
  528.     if ( OPCODE(inst) == RSkipLinesOp || OPCODE(inst) == REOFOp )
  529.         break;            /* <--- the other loop exit */
  530.     }
  531.  
  532.     /* If at end, skip the rest of a malformed image. */
  533.     if ( the_hdr->priv.get.scan_y >= the_hdr->ymax )
  534.     {
  535.     int y = the_hdr->priv.get.scan_y;
  536.     while ( rle_getskip( the_hdr ) != 32768 )
  537.         ;
  538.     return y;
  539.     }
  540.  
  541.     return the_hdr->priv.get.scan_y;
  542. }
  543.  
  544.  
  545. /* Fill buffer at s with n copies of character c.  N must be <= 65535*/
  546. /* ARGSUSED */
  547. static void bfill( s, n, c )
  548. register char *s;
  549. register int n, c;
  550. {
  551. #ifdef vax
  552.     asm("   movc5   $0,*4(ap),12(ap),8(ap),*4(ap)");
  553. #else
  554.     while ( n-- > 0 )
  555.     *s++ = c;
  556. #endif
  557. }
  558.